using System;
using System.Drawing;
using System.Windows.Forms;

namespace NKnobMan.Templatizer
{
    public class KnobControl : UserControl
    {
        private KnobTemplate _knobTemplate;
        private Rectangle hitTestPreviewBounds = Rectangle.Empty;
        private Size knobSize;
        private int spaceBetween = 5;
        private Point startPointPreview = Point.Empty;
        private PreviewMouseEvent testPreviewMouseEvent = PreviewMouseEvent.Normal;
        private double testPreviewRatio;
        private bool isStateDisabled = false;

        public KnobControl(KnobTemplate knobTemplate, Color backColor, Color foreColor)
        {
            SuspendLayout();
            Visible = false;
            _knobTemplate = knobTemplate;
            knobSize = _knobTemplate.KnobSize;
            SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

            BackColor = backColor;
            ForeColor = foreColor;

            int totalWidth = knobSize.Width + spaceBetween;
            totalWidth = (totalWidth < 64) ? 64 : totalWidth;
            Size = new Size(totalWidth, knobSize.Height + 64);

            hitTestPreviewBounds = _knobTemplate.GetDrawBounds(new Point(Width/2, Height/2));
            ResumeLayout(false);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            SolidBrush textBrush = new SolidBrush(ForeColor);

            TemplateIteration iteration = null;
            foreach (TemplateIteration iterationTemp in _knobTemplate.Iterations)
            {
                if (iterationTemp.Preview == testPreviewMouseEvent)
                {
                    iteration = iterationTemp;
                    break;
                }
            }

            if (iteration != null)
            {
                Point startDraw = new Point(Width/2, Height/2 );

                SizeF sizeOfText = e.Graphics.MeasureString(iteration.Name, Font);
                e.Graphics.DrawString(iteration.Name, Font, textBrush,
                                      new PointF(startDraw.X - sizeOfText.Width/2,
                                                 startDraw.Y - knobSize.Height/2 - spaceBetween -
                                                 sizeOfText.Height));
                
                int imageNumber = iteration.Draw(e.Graphics, startDraw, testPreviewRatio);

                string textImageNumber = "Image #" + imageNumber;

                sizeOfText = e.Graphics.MeasureString(textImageNumber, Font);
                e.Graphics.DrawString(textImageNumber, Font, textBrush,
                                      new PointF(startDraw.X - sizeOfText.Width / 2,
                                                 startDraw.Y + knobSize.Height / 2 + spaceBetween));
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (e.Button == MouseButtons.Left)
            {
                int delta = startPointPreview.Y - e.Location.Y;
                startPointPreview = e.Location;
                double inc = (double) 1/KnobMan.Default.PrefsRenderFrames;
                double largeInc = (KnobMan.Default.PrefsRenderFrames*0.10 + 1)/KnobMan.Default.PrefsRenderFrames;
                if (Math.Abs(delta) > 16)
                {
                    inc = largeInc*2;
                }
                else if (Math.Abs(delta) > 4)
                {
                    inc = largeInc;
                }
                inc = inc*Math.Sign(delta);
                testPreviewRatio += inc;
                if (testPreviewRatio < 0)
                {
                    testPreviewRatio = 0;
                }
                else if (testPreviewRatio > 1.0)
                {
                    testPreviewRatio = 1.0;
                }

                ChangeTestPreviewMouseState(PreviewMouseEvent.MouseClick);

                Refresh();
            }
            else if (hitTestPreviewBounds.Contains(e.Location))
            {
                ChangeTestPreviewMouseState(PreviewMouseEvent.MouseHover);
            }
        }

        private void ChangeTestPreviewMouseState(PreviewMouseEvent newEvent)
        {
            if (isStateDisabled)
            {
                newEvent = PreviewMouseEvent.Disable;
            }

            if (newEvent != testPreviewMouseEvent)
            {
                testPreviewMouseEvent = newEvent;
                Refresh();

                if (testPreviewMouseEvent == PreviewMouseEvent.Normal ||
                    testPreviewMouseEvent == PreviewMouseEvent.Disable)
                {
                    Cursor = Cursors.Default;
                }
                else
                {
                    Cursor = Cursors.SizeNS;
                }
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if ( hitTestPreviewBounds.Contains(e.Location))
            {
                if (e.Button == MouseButtons.Left)
                {
                    ChangeTestPreviewMouseState(PreviewMouseEvent.MouseClick);
                    startPointPreview = e.Location;
                } else if ( e.Button == MouseButtons.Right )
                {
                    isStateDisabled = true;
                    ChangeTestPreviewMouseState(PreviewMouseEvent.Disable);
                }
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            isStateDisabled = false;
            if (hitTestPreviewBounds.Contains(e.Location))
            {
                ChangeTestPreviewMouseState(PreviewMouseEvent.MouseHover);
            }
            else
            {
                ChangeTestPreviewMouseState(PreviewMouseEvent.Normal);
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (MouseButtons != MouseButtons.Left)
            {
                ChangeTestPreviewMouseState(PreviewMouseEvent.Normal);
            }
        }
    }
}